home *** CD-ROM | disk | FTP | other *** search
- /*
- *------------------------------------------------------------------------
- When handling odoc (Open Document), pdoc (Print Document) and
- similar AppleEvents, one sometimes needs to know the full directory
- path to the document being opened. The "standard" way of going about
- this is to obtain FSSpec from the AppleEvent record (or by coercing an
- AliasRecord), and use FSSpec's parent directory id to walk up the
- folder hierarchy (by repeatedly calling PBGetCatInfoSync())
- reconstructing the full path. It works just fine, but kind of tedious:
- filling out CInfoPBRec struct is rather messy. Recently I stumbled
- upon an easier and shorter way, for a programmer. It's based on two
- tricks:
- - AliasRecord gotten from AEDescList of an odoc event record
- is a minimal AliasRecord. We need the full record.
- - It's very easy to get volume, folder, file names from the
- full AliasRecord. No PBGetCatInfoSync() calls, at least, not by a
- programmer.
-
- Again, this technique (code below) would not probably save
- too many instructions a CPU has to execute; but it'll definitely help bump
- a few lines off the source code. One can also use these tricks to obtain
- the full file path from any other AppleEvent pertaining to file(s), or
- any AliasRecord or FSSpec for that matter.
-
- Converting a minimal alias (say, "pointed" to by an 'alias_handle') to
- the full one is a matter of four lines of code:
-
- FSSpec resolved_target;
- Boolean was_changed;
- do_well( ResolveAlias(0,alias_handle,&resolved_target,&was_changed) );
- do_well( UpdateAlias(0,&resolved_target,alias_handle,&was_changed) );
-
- The code below defines a function to do the trick, as well as a test
- driver to make sure the thing really works.
-
- The code has been compiled and tested with CodeWarrior 5-7.
- *------------------------------------------------------------------------
- */
-
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- // Execute a function 'ex' and make sure
- // it returns noErr
- #define do_well(ex) \
- { OSErr err = (ex); if( err != noErr ) \
- fprintf(stderr,"Failed call " #ex " with error %ld at line %ld of `%s'.", \
- err, __LINE__, __FILE__), exit(4); }
-
-
- // Get a full path from an alias record
- // Returns a pointer to a static string
- // Note, alias has to be a full alias
- // (minimal alias doesn't have directories record)
- const char * get_full_path(AliasHandle alias_handle)
- {
- static char path[700]; // Full path to return
- Str63 buffer;
- // Write a volume name at the beginning of
- // the path
- do_well( GetAliasInfo(alias_handle,asiVolumeName,buffer) );
- memcpy(path,(char *)buffer+1,buffer[0]);
- char * first_col_pos = path + buffer[0];
- *first_col_pos = ':'; // colon after the volume name
- char * after_ldir_pos = first_col_pos+1;
-
- // Put directory names from the parent upwards
- // In the string
- // Volume_name:Dir3:Dir2:Dir1:
- // first_col_pos points to the first : after
- // the volume name, after_ldir_pos points
- // after the last column. The new directory
- // retrieved from the alias record is wedged
- // between the volume name and first_col_pos
- for(register int dir_level=1;;dir_level++)
- {
- do_well( GetAliasInfo(alias_handle,dir_level,buffer) );
- if( buffer[0] == 0 )
- break; // no more (grand...dad) directories
- // Move [after_vname_pos,after_ldir_pos)
- // chunk forward to make room for this
- // (grand)parent directory
- char * p = after_ldir_pos;
- char * q = after_ldir_pos += buffer[0]+1; // reserve space for :
- assert( after_ldir_pos < path + sizeof(path) );
- while( p > first_col_pos )
- *--q = *--p;
- p = (char *)buffer+1+buffer[0]; // End of the (grand)parent dir name
- while( q > first_col_pos+1 )
- *--q = *--p;
- }
- // Get the file name itself and append it to the
- // end
- do_well( GetAliasInfo(alias_handle,asiAliasName,buffer) );
- assert( after_ldir_pos+buffer[0]+1 < path + sizeof(path) );
- memcpy(after_ldir_pos,(char *)buffer+1,buffer[0]);
- after_ldir_pos[buffer[0]] = '\0'; // Properly terminate the string
-
- return path;
- }
-
- // Test driver
- // Since getting an AppleEvent and taking
- // an AliasRecord from it is a bit of a hassle
- // we use a simpler test: convert a full file
- // name into an alias record, and get it back
- void main(void)
- {
- FSSpec file_spec;
- do_well(FSMakeFSSpec(0,0,"\pA System:SYSTEM FOLDER:HOSTS",&file_spec));
- AliasHandle alias; // Pretend this alias is from an AppleEvent
- do_well( NewAliasMinimal(&file_spec,&alias) );
-
- // Now do our trick of turning a min alias to a
- // full one (see comments above). Of course we could've
- // made the full alias right upfront above. But in
- // real applications, an alias from an odoc/pdoc/etc
- // AppleEvent is a min one, and we don't get any choice
- {
- FSSpec resolved_target;
- Boolean was_changed;
- do_well( ResolveAlias(0,alias,&resolved_target,&was_changed) );
- do_well( UpdateAlias(0,&resolved_target,alias,&was_changed) );
- }
-
- printf("\nThe full file name obtained from an alias is '%s'\n",
- get_full_path(alias));
-
- DisposHandle((Handle)alias);
- }
-